<?php

abstract class BaseForm { // абстрактный класс
	public $fields = array();
	public $isBound = false;
	
	public function __construct() {
		$this->configure();
	}
	
	abstract public function configure(); // Некоторая функция, которую должны определить дочерние классы
	
	public function addField($name, $label, $widget, $validator) {
		$this->fields[$name] = array(
			'value' => null,
			'label' => $label,
			'widget' => $widget,
			'validator' => $validator,
			'errors' => array()
		);
	}
	
	public function bind($values) {
		foreach ($this->fields as $name=>$field) {
			try {
				if (isset($values[$name])) {
					$this->fields[$name]['value'] = $values[$name];
				}
				$this->fields[$name]['value'] = $this->fields[$name]['validator']->clean($this->fields[$name]['value']);
			} catch (ValidatorError $e) {
				$this->fields[$name]['errors'][] = $e;
			}
		}
		$this->isBound = true;
	}
	
	public function isValid() {
		$result = $this->isBound;
		foreach ($this->fields as $field) {
			$result &= empty($field['errors']);
		}
		return $result;
	}
	
	public function render() {
		$html = '';
		foreach ($this->fields as $name=>$field) {
			$html .= $this->renderField($name, $field);
		}
		return $html;	
	}
	
	public function renderField($name, $field) {
		extract($field);
		$attributes = array(
			'id' => $name.'_field',
			'name' => $name
		);
		$labelHtml = '<label for="'.$attributes['id'].'">'.$label.'</label>';
		$errorsHtml = $this->renderErrors($errors);
		$widgetHtml = $widget->render($name, $value, $attributes);
		return $this->renderRow($labelHtml, $errorsHtml, $widgetHtml);
	}
	
	public function renderErrors($errors) {
		$html = '';
		foreach ($errors as $e) {
			$html .= '<li>'.$e->render().'</li>';
		}
		return $html;
	}
	
	public function renderRow($labelHtml, $errorsHtml, $widgetHtml) {
		$leftTh = '<th>'.$labelHtml.'</th>';
		$rightTd = '<td>';
		if (!empty($errorsHtml)) {
			$rightTd .= '<ul class="errors">'.$errorsHtml.'</ul>';	
		}
		$rightTd .= $widgetHtml.'</td>';
		return '<tr>'.$leftTh.$rightTd.'</tr>';
	}

	public function getValues() {
		$values = array();
		foreach ($this->fields as $name=>$field) {
			$values[$name] = $field['value'];
		}
		return $values;
	}
	
	public function getMethod() {
		return 'POST';
	}
	
	public function getSubmitLabel() {
		return 'Отправить';
	}
	
	
}
